#pragma once

#include "comm/my_str.h"
#include "comm/my_queue.h"
#include "comm/my_rbtree.h"
#include "comm/my_pool.h"


// consistent with http_headers.
// there may be multiple args with the same name in args.
// so we use same_args manage these args of the same name.
// the rbtree is used to quickly find the arg.
// queue_in_args is used to ensure the order of args.
// queue_in_same_args is used to manage args of the same name.

// NOTICE: the parsing args modified using this interface cannot guarantee its immutability.
// in this case, please use regular expressions or string operations.

typedef struct {
    my_queue_t                  queue_in_args;
    my_queue_t                  queue_in_same_args;
    my_str_t                    name;
    my_str_t                    value;
    /* if value not empty, the has_delimiter will be ignore. */
    unsigned                    has_delimiter;
} my_http_arg_t;

typedef struct {
    my_rbtree_node_t            tree_node;
    my_queue_t                  args;
    my_str_t                    name;
} my_http_same_args_t;

static inline void
my_http_same_args_init(my_http_same_args_t *same_args)
{
    my_queue_init(&same_args->args);
}

static inline int
my_http_same_args_cmp(my_rbtree_node_t *a, my_rbtree_node_t *b)
{
    my_http_same_args_t *args_a, *args_b;
    args_a = (my_http_same_args_t *)a;
    args_b = (my_http_same_args_t *)b;
    return my_str_case_cmp(&args_a->name, &args_b->name);
}

typedef struct {
    my_pool_t                   *pool;
    my_queue_t                  args;
    my_rbtree_t                 same_args_tree;
    my_rbtree_node_t            same_args_sentinel;
} my_http_args_t;

static inline void
my_http_args_init(my_http_args_t *args, my_pool_t *pool)
{
    args->pool = pool;
    my_queue_init(&args->args);
    my_rbtree_init(&args->same_args_tree,
        &args->same_args_sentinel,
        my_http_same_args_cmp);
}

// use this method to directly modify the value
// of the header without affecting the order of the header.
static inline void
my_http_arg_update(my_http_arg_t *arg, my_str_t *new_value)
{
    arg->value = *new_value;
}

// add http_arg to http_args and http_same_args.
// the end of the new adding will be append to the queue.
void my_http_args_add(my_http_args_t *args, my_http_arg_t *arg);

// use http_arg to cover http_same_args in http_args.
// the end of the new setting will be append to the queue.
void my_http_args_set(my_http_args_t *args, my_http_arg_t *arg);

// use name to get http arg.
// if has multiple args with the same name in headers,
// only the first one will be returend.
my_http_arg_t *my_http_args_get(my_http_args_t *args, my_str_t *name);

// return all args matching name.
// the http_args_add, http_args_set, http_adrs_del*
// may cause http_same_args to be modified.
// the same_args obtained before http_headers_add and http_headers_set
// can no longer be used.
my_http_same_args_t *my_http_args_values(my_http_args_t *args, my_str_t *name);

void my_http_args_del(my_http_args_t *args, my_http_arg_t *arg);

void my_http_args_del_by_name(my_http_args_t *args, my_str_t *name);

// dump arg for test
void my_http_arg_dump(my_http_arg_t *arg);

// dump same args for test
void my_http_same_args_dump(my_http_same_args_t *same_args);

// dump args for test
void my_http_args_dump(my_http_args_t *args);


// parser args str to http_args
// supports string parsing in the following format.
// 1. ""            ==> {}
// 2. "a"           ==> {"a": ""}               (empty value)
// 3. "a="          ==> {"a": ""}               (empty value)
// 4. "=1"          ==> {}                      (empty name)
// 5. "a=&b=1"      ==> {"a": "", "b": "1"}     (empty value)
// 6. "a&b=1"       ==> {"a": "", "b": "1"}     (empty value)
// 7. "=1&b=1"      ==> {"b": "1"}              (empty name)
// 8. "&b=1"        ==> {"b": "1"}              (empty name and value)
// 9. "&&b=1"       ==> {"b": "1"}              (empty name and value)
// if name empty, the current arg will be discarded.
// if value empty, the current arg value is "".
void my_http_args_parser(my_http_args_t *args, my_str_t *args_str);
// real data space is applied from the pool.
void my_http_args_to_string(my_http_args_t *args, my_str_t *dst_str);